<!DOCTYPE html>
<html>
	<head>
		<title>Sqrat Import - Module Import Library</title>
		
		<link type="text/css" href="style.css" rel="stylesheet" />
	</head>
	
	<body>
	
	<div id="header">
		<h1>Sqrat Import - Module Import Library</h1>
		<h3>(c) 2009 Brandon Jones</h3>
	</div>
		
	<div id="index">
		<h2>Table of Contents</h2>
		
		<ul>
			<li><a href="index.html">Home</a></li>
			<li><a href="binding.html">Binding Library</a></li>
			<li><a href="import.html">Module Import Library</a>
				<ul>
					<li><a href="#betaNotice">Beta Notice</a></li>
					<li><a href="#overview">Overview</a></li>
					<li><a href="#exposingImport">Exposing Import</a></li>
					<li><a href="#importing">Importing Modules</a></li>
				</ul>
			</li>
			<li><a href="threading.html">Threading Library</a></li>
		</ul>
		
	</div>
		
	<div id="text">
	
		<h2 id="betaNotice">Beta Notice</h2>
		
		<p>It should be noted that the import library as currently implemented is 
		considered to be in a "beta" state as feedback is gathered from the community.
		If issues or technical considerations are raised over the next few releases
		the C module interface may be updated. As such, while you are free to develop
		binary modules against it please keep an ear out for updates that may require
		existing modules to be adjusted.</p>
		
		<p>Also note that import is currently only available for Windows. If you would 
		like to assist in porting the import library to other platforms please contact 
		me!</p>
	
		<h2 id="overview">Overview</h2>
		
		<p>Sqrat 0.8 introduces support for the creation an importing of modules. 
		The modules may take one of several forms.</p>
		
		<ul>
			<li>A standard Squirrel script</li>
			<li>A squirrel script that has been compiled to bytecode</li>
			<li>A compiled C binary (ie: DLL)</li>
		</ul>
		
		<p>Each format has advantages and disadvantages, but in all cases the 
		ability to import modules allows you to more easily build, use, and distribute
		reusable code libraries.</a>
		
		<p>Sqrat Import is a standalone package and has no dependancy on the Sqrat Binding 
		library, and can be used independant of it.</p>
		
		<h2 id="exposingImport">Exposing Import </h2>

		<p>In order to access the import functionality in an embedded virtual machine
		the import library must first be registered. This is done much like the 
		registration of the squirrel standard libraries. First you must link to 
		"sqratimport.lib" (or .so or .a, depending on your system), then include the
		following in your source:</p>
		
	<pre>
	#include "sqratimport.h"
	
	// Create VM, register other libs, etc...
	sqrat_register_importlib(v);
	</pre>
		
		<p>Import functionality is now available to the registered virtual machine. Also
		note that the version of "sq" command line project packaged with sqrat registers
		the import library by default.</p>
		
		<h2 id="importing">Importing Modules</h2>
		
		<p>Importing a module from squirrel is fairly simple and flexible. At the most 
		basic level a module can be imported into the root table like so:</p>
		
	<pre>
	::import("modulename");
	</pre>
		
		<p>Notice that no extention was listed. Import will search first for a binary 
		module, followed by either a bytecode or script module. In all cases the exact
		nature of the module being loaded does not need to be known by the script writer
		and there is no difference in their usage. Binary modules will search the working
		directory first and then system directories as dictated by the systems standard 
		search order. Other modules will load from the working directory only at this 
		time.</p>
		
		<p>It is possible to provide import with a full path, although the extension
		should remain excluded. However, please note that doing so may introduce 
		cross-platform incompatibilities to your script.</p>
		
		<p>When a module is imported any tables, classes, instances, and variables it 
		exposes are imported into the target table. In the above example the target table
		was the root table, since none was specified. As such if the module exposed a class
		named "Foo", after importing it could be accessed like so:</p>
		
	<pre>
	::import("foomodule");
	f &lt;- ::Foo(); // Create a new instance of Foo
	</pre>
		
		<p>To specify a different table to import into, provide the target table as a
		second parameter. This allows you to encapsulate modules functionality in a 
		"namespace" of your choosing.</p>
		
	<pre>
	foo &lt;- {}; // Create a table to import into
	::import("foomodule", foo);
	f &lt;- foo.Foo(); // Create a new instance of Foo
	</pre>
		
		<p>Alternately, the target table is also returned by the import function, so the 
		following code has the same result.</p>
		
	<pre>
	foo &lt;- ::import("foomodule", {}); // Import into a new table, which will be assigned to foo
	f &lt;- foo.Foo(); // Create a new instance of Foo
	</pre>
		
		<p>Multiple modules can be imported into a single table, and a single module can be 
		imported into multiple tables if needed.</p>
		
	<pre>
	foo &lt;- {}; // Create a table to import into
	::import("foomodule", foo);
	::import("barmodule", foo); // foo now contains elements from foomodule and barmodule
	bar &lt;- ::import("barmodule", {}); // barmodule now is imported into both foo and bar
	</pre>
		
		<h2 id="scriptModules">Script Modules</h2>
		
		<p>A script module is just a normal squirrel script. The file should be given the 
		extension of ".nut", and there are some guidelines that should be followed when building
		a script intended for a module (detailed below) but otherwise it is no different than
		your average squirrel script. As an example:</p>
		
	<pre>
	// mymodule.nut
	class MyClass() {
		a = 1;
		b = "Hello";
	}
	
	function AddTwo(a, b) {
		return a + b;
	}
	
	PI &lt;- 3.1415;
	</pre>
	
	<pre>
	// importtest.nut
	mod &lt;- ::import("mymodule", {});
	
	instance <- mod.MyClass();
	::print(instance.a); // Will print "1"
	::print(instance.b); // Will print "Hello"
	
	res &lt;- mod.AddTwo(5, 3); // res == 8
	
	:print(mod.PI); // Will print "3.1415"
	</pre>
	
		<p>Looking at the example above, one might wonder what advantages there are to using 
		import over dofile in this scenario. The benefits are:</p>
		
		<ul>
			<li>Can transparently use the same method for binary and script modules</li>
			<li>Allows the user to import into a table of their choosing</li>
		</ul>
		
		<p>Otherwise, this function works identically to dofile for scripts.</p>
		
		<h2 id="binaryModules">Binary Modules</h2>
		
		<p>Binary modules take a bit more care to get up and running, but can be much more powerful.
		In a binary module you have access to any C/C++ libraries you want, and the code can execute
		much faster.</p>
		
		<p>Binary modules must expose a single C function with the following signature:</p>
		
	<pre>
	SQRESULT sqmodule_load(HSQUIRRELVM v, HSQAPI sq);	
	</pre>
	
		<p>This function will be called when the module is imported. It is responsible for doing any
		setup needed for the module. Interaction with squirrel is done via the standard squirrel C API.
		</p>
		
		<p>The two parameters expose the required interfaces for interacting with squirrel from within 
		the module. The HSQUIRRELVM is the squirrel virtual machine to import into. The HSQAPI is a 
		pointer to a struct of function pointers containing all calls of the core squirrel API. Function 
		names remain the same with the exeption of being stripped of the "sq_" prefix. So a call to 
		sq_newtable() would be made within the module as sq->newtable(). This allows modules to be developed
		without linking to the squirrel library, which can help decrease module size when built. You will 
		likely want to save this pointer for later use within the module. The pointer will not be deleted 
		while the module is loaded, so it is safe to store the pointer. You should not attempt to delete 
		the or alter the HSQAPI pointer, since this may lead to undefined behavior. HSQAPI is defined in 
		"sqmodule.h"</p>
		
		<p>When the squirrel module is called, the table to import into will be the top item on the stack.
		You are free to manipulate the stack however you choose while setting up the module, it will be set
		back to it's original state when sqmodule_load exits.</p>
		
		<p>If the module is able to load successfully you should return SQ_OK, otherwise return SQ_ERROR.</p>
		
		<p>The following is a sample of a very simple C++ module (Windows).</p>
		
	<pre>
	// simplemodule.h
	
	#if !defined(_SIMPLEMODULE_H_)
	#define _SIMPLEMODULE_H_

	#include "sqmodule.h"

	#ifdef __cplusplus
	extern "C" {
	#endif

		__declspec(dllexport) SQRESULT sqmodule_load(HSQUIRRELVM v, HSQAPI api);

	#ifdef __cplusplus
	}
	#endif

	#endif
	</pre>
	
	<pre>
	// simplemodule.cpp
	
	#include "simplemodule.h"
	HSQAPI sq;
	
	SQInteger modhello(HSQUIRRELVM v) {
		sq-&gt;pushstring(v, _SC("Hello Squirrel Module!"), -1);
		return 1;
	}

	// Module registration
	SQRESULT sqmodule_load(HSQUIRRELVM v, HSQAPI api) {
		sq = api;

		sq-&gt;pushstring(v, _SC("hello"), -1);
		sq-&gt;newclosure(v, &amp;modhello, 0);
		sq-&gt;newslot(v, -3, 0);
		
		return SQ_OK;
	}
	</pre>
	
		<p>Usage:</p>
	
	<pre>
	// simplemoduletest.nut
	
	::import("simplemodule");
	::print(hello()); // Will print "Hello Squirrel Module!"
	</pre>
	
		<p>A more full example can be seen in the sqratthread project included with squirrel.</p>
	
		<h2 id="scriptModules">Module Guidelines</h2>
		
		<p>When building a module, especially when it is intended for use by other developers,
		there are several guidelines that should be adhered to to produce predictable behavior.</p>
	</div>
	</body>
</html>